/*
    Dominate 3D - A cube-based game of life

    Copyright (C) 2007, Craig H. Miller (kidmosey@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CUBE_H__
#define __CUBE_H__

#include "matrix.h"
#include "cell.h"

#include <vector>

class Player;

class Cube
{
public:
    Cube();
    ~Cube();

    Cube(int cells_per_face);
/*
    Cube(const Cube &copy);
*/

    const CMatrix &GetMatrix() const;
    void Render() const;

    void Subdivide();
    void CalculateNeighbors();
    float GetTimeElapsed() const;

    void ResetRotation();
    void Generate(int dimXY);

    void ApplyRotation(const CVector3D &rot);

    Player *GetCurrentPlayer();

    std::vector<Cell *> GetCellsAt(const CVector3D &v);
    std::vector<Cell *> GetStartCells(Player *player);

    void AddPlayers(std::vector<Player *> &players);
    void RemovePlayer(int id);

    bool CanMove(Player *p);
    Cell *GetCell(int cellID);

    std::vector<CellStats> GetCellStats(Player *player) const;

    // get the totals for cell owners
    int CountSurroundingCells(Cell *cell, std::map<Player *, int> &counts) const;
    int GetNumPlayers() const { return m_listPlayers.size(); }
    void AddPlayer(Player *p)
    {
        m_listPlayers.push_back(p);

        if (m_listPlayers.size() == 1)
            m_currentPlayer = m_listPlayers.begin();
    }
    Player *GetPlayer(int id);
    void IncrementPlayer();
    void SetCurrentPlayer(int id);

    void Update();
    bool IsFull() const;

    std::vector<Cell *> m_listCells;
    Cell *m_selectedCell;
    std::vector<Player *> m_listPlayers;

    CVector3D m_vRotVelocity;

private:
    bool m_isFull;

    void RemovePlayerCells(Player *p);

    float m_timerStart;
    CMatrix m_matRotation;
    std::vector<Player *>::iterator m_currentPlayer;
    CVector3D m_listVerts[8];

    void InitVertices();
    void AttachNeighbors(Cell *cell);
    void GenerateFace(const CVector3D &vecNormal, const CVector3D &vecRight, const CVector3D &vecDown, float delta);

    class Edge
    {
    public:
        Edge(const CVector3D &a, const CVector3D &b): ptA(a), ptB(b)
        { }

        ~Edge()
        { }

        bool operator== (const Edge &rhs)
        {
            return (ptA == rhs.ptA && ptB == rhs.ptB) ||
                   (ptA == rhs.ptB && ptB == rhs.ptA);
        }

        CVector3D ptA, ptB;
    };

};

#endif // __CUBE_H__
